#include "io430.h"
#include <cstdlib>
#include <time.h>

#define MHz10   10000
#define MHz100  1000

#define SIZE    10

typedef int (*functPtr)(int, int);

//Define struct representing statistics of the process
typedef struct{
 int numInstruc;
 int deadline; 
}SuProcStats;

//Define all process functions
int process(int speed, int instructs);
int setupQueue(SuProcStats *statistics, int size);
int totalInstruct(SuProcStats *stats, int size);
int determineSpeed(int totalI, int timeLeft);
int findProc(int overhead, SuProcStats *stats, int size);
  
//Assuming that when device starts it has 300 seconds to 
//run all processses.
#define DEADLINE  300 //seconds

int main(void)
{
  //Turn off watchdog timer.
  WDTCTL = WDTPW + WDTHOLD;
  
  //Create a scheduling queue.
  SuProcStats procQueue[SIZE];
  int index = 0;
  int success = -1;
  int timeLeft = DEADLINE;
  int overhead = 0;
  int nextProc = 0;
  int queuedI = 0;
  
  //Setup process queue.
  success = setupQueue(&procQueue[0], 10);  
  
  //Verify that it was successful.
  if(success != 0){
    return -1;
  }
  
  queuedI = totalInstruct(&procQueue[0], SIZE);
  
  while(queuedI > 0){
    
    overhead = queuedI/10 - timeLeft;
    if(overhead > 0){
       nextProc = findProc(overhead, &procQueue[0], SIZE);
       process(MHz100, procQueue[nextProc].numInstruc);
       timeLeft = timeLeft - (procQueue[nextProc].numInstruc/100);
       procQueue[nextProc].numInstruc = 0;
    }else{
      //fillQueue(&procQueue[0], SIZE);
      for(index = 0; index < SIZE; index++){
        if(procQueue[index].numInstruc != 0){
          process(MHz10, procQueue[index].numInstruc);
          timeLeft = timeLeft - (procQueue[nextProc].numInstruc/10);
          procQueue[index].numInstruc = 0;
        }
      }
    }
  
    queuedI = totalInstruct(&procQueue[0], SIZE);
  }    
  return 0;
}

int findProc(int overhead, SuProcStats *stats, int size){
  int nextProc = 0;
  int i = 0;
  if(size < 1){
    return -1; 
  }
  
  if(overhead % 10 != 0)
  {
    overhead = overhead - (overhead%10); //get rid of the remainder 
    overhead += 10; //round up
  }
  
  for(i = 0; i < size; i++){
    if(stats[i].numInstruc == 0){
      //do nothing
    }
    else if(overhead - stats[i].numInstruc/10 < 0){ //too many instructions
      i = size; 
    }else{
      nextProc = i; 
    }
  }
  
  return nextProc;
}
/*
void runReadyQueue(SuProcStats *stats, int size){
  int i;
  
  if(size < 1){
    return; 
  }
  
  for(i = 0; i < size; i++){
    process(stats[i].speed, stats[i].numInstruc);
  }
}

void fillQueue(SuProcStats *stats, int size){
  int i;
  
  if(size < 1){
    return; 
  }
  
  for(i = 0; i < size; i++){
    if(stats[i].queued == -1){
      stats[i].queued = 1;
      stats[i].speed = MHz10;
    }
  }
}*/

int totalInstruct(SuProcStats *stats, int size){
  int index;
  int numInstructs = 0;
  if(size < 1){
   return -1; 
  }
  
  for(index = 0; index < size; index++){
    if(stats[index].numInstruc != 0){
      numInstructs += stats[index].numInstruc;
    }
  }
  
  return numInstructs;
}

int process(int speed, int instructs){
  int i = 0;
  int j = 0;
  int blinkSpeed = 0;
  
  switch(speed){
  case MHz10:
    blinkSpeed = 10000;
    P1DIR = 0x02;
    break;
  case MHz100:
    blinkSpeed = 5000;
    P1DIR = 0x01;
    break;
  default:
    break;
  }
  
  while(i < instructs){ 
    if(speed == MHz100){
      P1OUT ^= 0x01;
    }else{
      P1OUT ^= 0x02; 
    }
    for(j=0; j < blinkSpeed; j++){
      __no_operation(); 
    }
    i++;
  }
  
  P1DIR = 0x00;
  
  for(j=0; j < 10000; j++){
    __no_operation(); 
  }

  return 0;
}

int setupQueue(SuProcStats *statistics, int size){
  int index;
  int totalInstructs;
  if(size < 1 ){
   return -1; 
  }
  
  for(index = 0; index < size; index++){
    totalInstructs = index*100 + 100;
    statistics[index].numInstruc = totalInstructs;
    statistics[index].deadline = 300; //seconds
  }
  
  return 0;
}